﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TrackManager : MonoBehaviour
{
	public GameObject m_TrackPiecePrefab;
	public GameObject m_DeadEndPiecePrefab;
	public GameObject m_TrackHolder;
	private GameObject m_LastTrackPiece;
	public float m_speed = 1f;
	public float m_initialSpeed = 1f;

	private GameObject m_FollowTrackPiece;
	SplineList m_followSplineList;
	private Vector3 m_tracksInitialPosition;
	private float m_elapsedTime = 0f;
	public GameObject m_train;
	private bool m_moving = false;
	public float m_acceleration = 1f;

	Queue<GameObject> m_trackList = new Queue<GameObject>();

	void Start ()
	{
		m_initialSpeed = m_speed;
		m_LastTrackPiece = CreatePiece(m_TrackPiecePrefab);
		m_FollowTrackPiece = m_LastTrackPiece;
		m_followSplineList = m_FollowTrackPiece.GetComponent<SplineList>();
		m_followSplineList.CacheVectors();

		// initial positions
		m_TrackHolder.transform.position = m_LastTrackPiece.transform.position - m_followSplineList.GetPosition(0f);
		m_tracksInitialPosition = m_TrackHolder.transform.position;
	}

	GameObject CreatePiece(GameObject prefab)
	{
		GameObject piece = (GameObject)Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity);
		piece.transform.parent = m_TrackHolder.transform;
		SplineList splineList = piece.GetComponent<SplineList>();
		if(splineList) splineList.m_train = m_train;

		return piece;
	}

	Transform GetInConnector(GameObject piece)
	{
		Transform[] children = piece.GetComponentsInChildren<Transform>();
		foreach (Transform child in children)
		{
			if (child.name == "InConnector")
			{
				return child;
			}
		}
		Debug.Log("Where is your inConnector? huh?");
		return piece.transform;
	}

	void AppendTrack()
	{
		// get the out connectors of the last track piece
		Transform[] lastTrackChildren = m_LastTrackPiece.GetComponentsInChildren<Transform>();
		List<Transform> outConnectors = new List<Transform>();
		foreach (Transform child in lastTrackChildren)
		{
			if (child.name == "OutConnector")
			{
				outConnectors.Add(child);
			}
		}

		// go through all the out connectors and attach a new piece, pick one at random to attach a "good" track
		int size = outConnectors.Count;
		int index = Random.Range(0, size);
		for (int i = 0; i < size; ++i)
		{
			Transform currentChild = outConnectors[i];
			if (i == index)	//attach "good" track
			{
				GameObject piece = CreatePiece(m_TrackPiecePrefab);
				Transform inConnector = GetInConnector(piece);
				piece.transform.position = currentChild.position;
				piece.transform.position = piece.transform.position + (piece.transform.position - inConnector.position);
				m_trackList.Enqueue(piece);
				m_LastTrackPiece = piece;
			}
			else	//attach "bad" track
			{
				GameObject deadEnd = CreatePiece(m_DeadEndPiecePrefab);
				Transform inConnector = GetInConnector(deadEnd);
				deadEnd.transform.position = currentChild.position;
				deadEnd.transform.position = deadEnd.transform.position + (deadEnd.transform.position - inConnector.position);
			}
		}
	}

	void PopulateTracks()
	{
		if (m_LastTrackPiece)
		{
			while (m_LastTrackPiece.renderer.isVisible)
			{
				AppendTrack();
			}
		}
	}
	
	void Update ()
	{
		PopulateTracks();

		if (m_moving)
		{
			m_elapsedTime += Time.deltaTime;
			float t = m_speed * m_elapsedTime;

			m_speed += m_acceleration * Time.deltaTime;

			m_TrackHolder.transform.position = m_tracksInitialPosition - m_followSplineList.GetPosition(t);

			if (t >= 1f)
			{
				m_FollowTrackPiece = m_trackList.Dequeue();
				m_followSplineList = m_FollowTrackPiece.GetComponent<SplineList>();

				m_followSplineList.CacheVectors();
				m_elapsedTime = 0f;
				m_tracksInitialPosition = m_TrackHolder.transform.position;
			}
		}
	}

	void DestroyAllTracks()
	{
		foreach (Transform child in m_TrackHolder.transform) {
			GameObject.Destroy(child.gameObject);
		}
	}

	public void ResetTracks()
	{
		m_trackList.Clear();
		DestroyAllTracks();
		m_TrackHolder.transform.position = new Vector3();
		m_LastTrackPiece = CreatePiece(m_TrackPiecePrefab);
		m_FollowTrackPiece = m_LastTrackPiece;
		m_followSplineList = m_FollowTrackPiece.GetComponent<SplineList>();

		m_followSplineList.CacheVectors();
		// initial positions
		m_TrackHolder.transform.position = m_LastTrackPiece.transform.position - m_followSplineList.GetPosition(0f);
		m_tracksInitialPosition = m_TrackHolder.transform.position;
		m_followSplineList.CacheVectors();

		m_elapsedTime = 0f;
		m_speed = m_initialSpeed;
	}

	public void StartTracks()
	{
		m_moving = true;
	}

	public void StopTracks()
	{
		m_moving = false;
	}
}